home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 49 / Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso / -serious- / misc / mmulib / autodocs / exceptions.doc < prev    next >
Text File  |  1999-11-29  |  36KB  |  808 lines

  1.         E X C E P T I O N - H A N D L E R   D E T A I L S
  2. ------------------------------------------------------------------------------
  3. Abstract:
  4.     This document defines the exception handler mechanism of the mmu.library
  5.     and how to make use of it.
  6.     Please study it carefully before you try to implement an mmu.lib
  7.     exception handler. 
  8.  
  9.     For details about the concepts of a "context", read the mmu.doc.
  10. ------------------------------------------------------------------------------
  11. What is a bus error exception:
  12.  
  13.     A bus error can be understood as a sort-of "interrupt" which is triggered
  14. by either a software fault or a hardware signal related to acessing memory
  15. or external devices in an unsupported fashion, like accessing a non-available
  16. memory location or writing to a write-protected memory region.
  17.  
  18. All bus errors are re-directed to the MMU.library, but some of them remain
  19. unhandled and are passed over to the exec.library. Some of the remaining
  20. errors are handled automatically by the library, and those that remain
  21. will cause your "context hooks" to be called, as installed by the
  22. "AddContextHook" and "AddMessageHook" vectors of the mmu.library.
  23.  
  24.  
  25. The members of the MC680x0 family generate so called "bus error" for the
  26. following situations:
  27.  
  28. - True physical bus errors: 
  29.  
  30.     The CPU tried to access an external device, but this request was aborted
  31.     by pulling the "bus error input" control line (TEA) of the CPU low. 
  32.     These bus errors are generated by an external bus control logic, avail-
  33.     able for some Amiga models, on access of non-available memory.
  34.  
  35. - Access errors:
  36.  
  37.     These errors are generated by the MMU for a non-valid access of
  38.     a memory "page". As far as the MMU is concerned, complete memory is
  39.     split into adjacent pages of a fixed size, usually of size 1K or 4K,
  40.     and the MMU holds access rules, the so called "properties" for each
  41.     of these pages. If these rules are violated, an access error is
  42.     generated. The following violations may arise:
  43.  
  44.     The CPU tried to access a page of memory marked by the MMU as 
  45.     "non-resident", or tried to write to a memory block which is write-
  46.     protected, or tried to access a memory block in user mode which is
  47.     marked as "supervisor only" access.
  48.  
  49. Of all of these bus errors, the mmu.library handles only the part which it
  50. is "interested in". True physical bus errors are not handled by the 
  51. MMU.library and passed thru to the exec exception handler - which again, calls
  52. the exception handler of the task that caused the exception. Additionally,
  53. the MMU.library does not try to fix bus errors caused by so called "locked
  54. transfers", i.e. the instructions "TAS","CAS" and "CAS2". These instructions
  55. are only useful for multi-processor machines and not supported by the Amiga
  56. hardware architecture anyways. A legal Amiga program *must not* use them.
  57.  
  58. Furthermore, the "MOVE16" instruction accesses of the 040 and 060 processors
  59. are not handled, too, for the same reason. All these errors are passed thru
  60. to exec, and remain unhandled. They will usually force a fatal software 
  61. failure.
  62.  
  63. An additional special case - which might be interesting for the experts -
  64. is writing to memory by "instruction function code". This is only possibly
  65. by loading this function code to the "dfc" register and then using the
  66. privileged "moves" instruction to write instruction data. This is unsupported,
  67. too. Just write instructions with "move", then flush the cache. This is, too,
  68. what the dos.library does when loading code.
  69.  
  70.  
  71. All remaining accesses are handled by the MMU library, and are first filtered
  72. again. The MMU library distinguishes:
  73.  
  74. -    User mode and supervisor mode accesses.
  75.  
  76. All exec tasks MUST run in user mode, and this is the "default" situation.
  77. The user mode exceptions are handled according to the "MMU context" they
  78. are generated by, or, equivalently, the context the current task is attached
  79. to. All supervisor mode accesses are managed by one single context, the 
  80. "supervisor context".
  81.  
  82. -    Data vs. instruction accesses.
  83.  
  84. Whether the bus error happened due to faulted access of data, or whether 
  85. the CPU tried to fetch instructions, and this instruction fetch faulted.
  86. Instruction write accesses, as they might have been generated by a "moves",
  87. might or might not be handled, this is implementation specific. The CPU
  88. itself never generates these accesses when fetching code, the only 
  89. possibility is a "moves" instruction.
  90.  
  91. -    Read vs. write accesses.
  92.  
  93. Whether data was about to be read by the CPU, or the CPU tried to write
  94. out data. Instruction accesses by the CPU are always of reads.
  95. Accesses to the stack, as for subroutine calls or "link" instructions
  96. are regarded as data accesses, too. (Read about special caveats about
  97. the stack, below!)
  98.  
  99. Amongst all these types, the MMU library handles certain special cases
  100. automatically. You never see these faults from your context hooks, they
  101. are completely transparent and handled by the library as a special service.
  102.  
  103. -     AbsExecBase reads.
  104.  
  105. To be able to mark the first memory page as "invalid", the MMU library
  106. filters out accesses to AbsExecBase itself in the first stage of the exception
  107. handler, to emulate them as fast as possible. The library will try to emulate
  108. the most popular instructions in software, for optimal performance. However,
  109. still try to avoid reading AbsExecBase in your code. Make a copy to a static
  110. library base on startup, and then use this backup copy whenever possible.
  111. Most modern C compilers do that automatically anyways, but assembly language
  112. authors should keep this in mind.
  113.  
  114.     DON'T (slow!)                            DO (fast)
  115.  
  116.     move.l AbsExecBase,a6                    move.l mn_SysBase(a4),a6
  117.  
  118.  
  119. In case the special threatment of AbsExecBase is not desired, set the 
  120. MCXTAG_EXECBASE tag value of the CreateMMUContext() call to FALSE. This might
  121. be interesting for emulators, for example.
  122.  
  123. Remember that interrupt code is handled by the supervisor context, AND NOT
  124. BY YOUR USER CONTEXT. Hence, accessing AbsExecBase from within interrupts is
  125. always valid, simply because the supervisor context is always build by the
  126. library itself, and this flag is always set on creation of this context. 
  127. DO NOT touch the supervisor context unless you know precisely what you're
  128. doing.
  129.  
  130.  
  131. -    Accesses above 0x0400 in the first memory page.
  132.  
  133. The mmu.library emulates accesses above addresses 0x0400 to the first
  134. page in memory. This is again to allow setting the first page to "invalid"
  135. for tracing access errors in the autovector region. Accesses to addresses
  136. above and including 0x400 in the first page are therefore always legal.
  137. This feature can be disabled again with the MCXTAG_EXECBASE flag, see above.
  138.  
  139. AVOID THESE ACCESSES, THEY ARE EMULATED IN SOFTWARE AND VERY SLOW.
  140.  
  141. Starting with Os 3.0, exec tries to help these MMU programs by starting 
  142. chip memory at 0x1000, not at 0x0400 as usual, if a 040 or 060 CPU is
  143. available. This means that for page sizes of 4K for the 040 and 060, and
  144. for page sizes of 1K for the 030 and 68851/020 MMU, no accesses need to
  145. be emulated. Please keep this in mind when using the MMU because THE 
  146. EMULATION CODE IS SLOW. Try to use these "natural" page sizes whenever 
  147. possible.
  148.  
  149. If not possible, try to relolate the libraries and buffers in this memory
  150. region, usually some graphics.library buffers, the expansion library base,
  151. and - possibly - the exec library.
  152.  
  153. Trying to execute code in this memory region does work, but is really, really
  154. slow. Each instruction access has to go thru the mmu.library exception
  155. handler, so feel prepared that your computer runs in "slo-mo mode" if you
  156. don't follow these rules.
  157.  
  158.  
  159. - Writes to MAPP_ROM pages.
  160.  
  161. The mmu.library tries to cancel writes to pages marked as "ROM". Writes
  162. to these pages will generate an access error, which is "ignored" by
  163. the mmu.library. Hence, memory regions marked as "ROM" will get an
  164. effective "silent" write protection. However, keep in mind that a write
  165. to "ROM" area is still slow because it includes running the exception handler.
  166. This goes even more for the 060 CPU because it includes copying the "ROM"
  167. to a dummy writable backup page into which the write is then redirected.
  168.  
  169. Special care must be taken for "misaligned" writes, i.e. writes that hit
  170. the "border" of a ROM region and go partially into valid RAM, and partially
  171. into "ROM" regions. The MMU.library DOES NOT guarantee that the valid part
  172. of the access is performed! It might abort the complete write!
  173.  
  174. This shouldn't be much of a problem because writes to ROM should only happen
  175. due to faulty software, and it should only do good to abort these writes
  176. completely.
  177.  
  178.  
  179. To say that again: All the cases above are handled by the library trans-
  180. parently, you don't see them from your context hook. However, the following
  181. cases ARE seen from your hook function:
  182.  
  183.  
  184. - Access to MAPP_SWAPPED pages.
  185.  
  186. If a read or write hits a page marked as swapped, the library calls all
  187. hooks in its "swapped" hook list. For details what happens then, see below.
  188.  
  189. Again, special care must be taken if the access is "misaligned", i.e. hits
  190. more than one page at once. In this case, the library checks if both accesses
  191. are allowed, i.e. go either to valid pages, or to swapped pages. In case
  192. any of the accesses is invalid, the "segmentation fault" hook list, see 
  193. below, is called.
  194.  
  195.  
  196. - Any other access,
  197.  
  198. as there are accesses to "MAPP_INVALID" pages or to supervisor only pages
  199. in user mode, or write accesses to write protected pages are passed over
  200. to the "segmentation fault" hook list.
  201.  
  202.  
  203. How your hook function is called:
  204. ---------------------------------
  205.  
  206. The mmu.library keeps two priority sorted lists for each MMU context, one
  207. for the "swapped" hook list for pages currently "swapped out", and another
  208. for the "segmentation fault" hook lists. The mmu library first determinates
  209. which list has to be used to handle the access, and then tries to find the
  210. right handler. The following algorithm is used:
  211.  
  212.     - Try the handler of higher priorities first;
  213.     - Check whether this hook is activated or not, skip it if it is
  214.       deactivated;
  215.     - Check whether the hook is "task specific", i.e. whether the
  216.       MADTAG_TASK tag was given at the time the hook was added with
  217.       AddContextHook().
  218.       If the hook is task specific, check whether the faulty task
  219.       is identical to the task handled by the hook and skip the
  220.       handler if this is not the case.
  221.     - As soon as a match has been found, call the routine at the
  222.       address provided by the MADTAG_CODE tag. This should be an
  223.       assembly routine, mainly for speed reasons. Furthermore,
  224.       parameters are passed in registers, similar to the exec.library
  225.       interrupts, and return values have to be provided in the d0
  226.       register and in the "Z" bit of the processor.
  227.  
  228. You're called like this:
  229.     
  230.     Register a0 contains a pointer the exception data structure,
  231.     discussed below.
  232.  
  233.     Registers a1 and a4 contain the data provided by the MADTAG_DATA
  234.     tag on creation.
  235.  
  236.     Register a6 contains the pointer to the mmu.library base.
  237.  
  238.     Register a5 contains the pointer to your code.
  239.  
  240. You may alter registers d0-d1, a0-a1 and a4-a5. They will be restored by the 
  241. library automatically. All other registers MUST BE preserved.
  242.  
  243. In case you want make use of the exception data structure, please keep in 
  244. mind that it is only valid as long as your exception hook executes. That 
  245. means that you possibly have to make a copy of it for later use.
  246.     
  247. Remember, too, that you're called in supervisor mode, with all interrupts
  248. disabled. DO NOT ACCESS ABSEXECBASE IN YOUR CODE, use either a private
  249. copy, or the copy in the ExceptionData structure below. Accessing
  250. AbsExecBase MIGHT BE FATAL!
  251. Additionally, THERE IS NO DIRECT ACCESS to the CPU specific exception
  252. stack frame. Exception hooks are - and that's the great point about the
  253. mmu library - CPU indepentent. All data you need is provided in the
  254. exception data structure, DO NOT MAKE ANY ASSUMPTIONS which CPU you're 
  255. running at, or how the stack frame looks like. This is the matter of the
  256. library.
  257.  
  258.  
  259. On return, you should set d0 to 0 and set the zero flag to indicate that
  260. your exception handler was able to handle the fault and return to the
  261. library with a plain "RTS". In that case, the library will no longer look 
  262. for more handlers.
  263. If you haven't been able to handle the fault, return 1 in d0 and clear
  264. the zero flag (i.e. return a "ne" condition in the CCR register). 
  265.  
  266. In case the library did not find any hook that claimed to be able to 
  267. repair the fault, it will redirect control back to the exec exception
  268. handler (which will, by default, run the GURU).
  269.  
  270. BE WARNED! Another bus error within the bus error handler IS FATAL AND WILL
  271. CAUSE A GURU! Within the exception handler, YOU MUST ENSURE that all memory
  272. accesses are valid or you're lost. The library function GetPagePropertiesA() 
  273. is ideal for this purpose: First, it is safe to get called within interrupts
  274. and bus errors, it is rather optimized and you find all information required
  275. to call it in the ExceptionData structure.
  276.  
  277. The ExceptionData structure
  278. ---------------------------
  279.  
  280. This structure is the key to the powers of the MMU. Your handler is called
  281. with a pointer in *a0 to this structure:
  282.  
  283. struct ExceptionData {
  284.     struct Task                *exd_Task;
  285.     struct MMUContext        *exd_Context;
  286.     ULONG                    *exd_Descriptor;
  287.     ULONG                    *exd_NextDescriptor;
  288.     APTR                     exd_FaultAddress;
  289.     APTR                     exd_NextFaultAddress;
  290.     ULONG                     exd_UserData;
  291.     ULONG                     exd_NextUserData;
  292.     ULONG                     exd_Data;
  293.     APTR                     exd_ReturnPC;
  294.     ULONG                     exd_Flags;
  295.     ULONG                     exd_Properties;
  296.     ULONG                     exd_NextProperties;
  297.     UBYTE                     exd_internal;
  298.     UBYTE                     exd_FunctionCode;
  299.     UBYTE                     exd_Level;
  300.     UBYTE                     exd_NextLevel;
  301.     ULONG                     exd_DataRegs[8];
  302.     ULONG                     exd_AddrRegs[7];
  303.     UWORD                    *exd_SSP;
  304.     UWORD                    *exd_USP;            
  305.     struct ExecBase            *exd_SysBase;
  306.     struct MMUBase            *exd_MMUBase;
  307. };
  308.  
  309. Let's discuss the fields in this structure:
  310.  
  311. exd_Task        contains the pointer to the task structure of the task 
  312.                 that caused the exception.
  313.                 If this hook was added to the supervisor context, this
  314.                 field is meaning less and must be left alone.
  315.  
  316. exd_Context        contains the ID of the MMU context responsible for the
  317.                 fault. This is always the context the hook was added to.
  318.  
  319. exd_Descriptor    contains a pointer to the true hardware MMU descriptor which
  320.                 handles the fault. This is usually of less interest except
  321.                 for special purposes.
  322.                 In case of an indirect descriptor, this points NOT to the
  323.                 final page descriptor, but to the indirect descriptor.
  324.  
  325.                 WARNING! In case you read this descriptor or write a new
  326.                 one, you *MUST* call CacheClearE() to make sure that the
  327.                 descriptor is really written out. The library will always
  328.                 flush descriptors correctly.
  329.  
  330. exd_NextDescriptor    In case of a misalgined access, i.e. an access that
  331.                 spawns two pages because it hit a page boundary, this is the 
  332.                 descriptor for the end address of the access, and 
  333.                 exd_Descriptor is the descriptor for the first address
  334.                 of the access. If the access is aligned, both pointers are
  335.                 identically.
  336.                 NOTE THAT THIS DESCRIPTOR NEED NOT TO POINT TO A HIGHER
  337.                 ADDRESS. An example for a "backwards" misaligned access is
  338.                 the "movem.l regs,-(ax)" instruction.
  339.  
  340.                 WARNING! In case you read this descriptor or write a new
  341.                 one, you *MUST* call CacheClearE() to make sure that the
  342.                 descriptor is really written out. The library will always
  343.                 flush descriptors correctly.
  344.             
  345. exd_FaultAddress    
  346.                 The address that faulted, the start address of the access.
  347.  
  348. exd_NextFaultAddress    
  349.                 The end address of the access that faulted, inclusive.
  350.                 For a long word access, this would be exd_FaultAdress + 3,
  351.                 for a byte access, this would be identically to 
  352.                 exd_FaultAdress.
  353.                 Note that it may well be that exd_NextFaultAddress is a
  354.                 SMALLER address than exd_FaultAdress. This might, for example,
  355.                 happen for a movem with pre-decrement addressing mode, i.e.
  356.                 a "movem.l d0-d7/a0-a6,-(a7)". Exception handlers must be
  357.                 aware of this special situation.
  358.  
  359. exd_UserData    The user data provided for invalid and swapped pages, as
  360.                 defined by SetPropertiesA() and SetPagePropertiesA().
  361.                 This will be NULL in case no user data is available.
  362.  
  363. exd_NextUserData
  364.                 In case of a misalgined access, the user data of the
  365.                 second page that was involved in the exception. If the
  366.                 access was aligned, this is identical to exd_UserData.
  367.  
  368. exd_Data        If the access was a write access and the 
  369.                 EXDF_WRITEDATAUNKNOWN flag (see below) is cleared, then
  370.                 this long word will contain the data the CPU tried to
  371.                 write out. The data is right-justified in this field, i.e.
  372.                 bytes will use bits 7..0, words will use bits 15..0 and
  373.                 long word accesses will use the complete field.
  374.                 The size is available by subtracting the exd_FaultAddress and
  375.                 exd_NextFaultAddress fields.
  376.                 On movem faults, the complete write data is unfortunately
  377.                 not available. You may see movem faults as a series of
  378.                 long word writes on some CPUs, while this instruction is
  379.                 atomic on other CPUs. There's nothing the MMU library can
  380.                 do for you here.
  381.                 This data should be used only for debugging purposes and
  382.                 "Enforcer like" applications, and for applications where you
  383.                 can guarantee that movems do not occur, i.e. emulators that
  384.                 threat "computer hardware" by the MMU and might read the
  385.                 data written to the emulated hardware right here.
  386.  
  387.                 To allow the MMU library to fetch write data, you *MUST*
  388.                 set the "MAPP_REPAIRABLE" bit of pages you want write data
  389.                 for. In all other cases, you *might* get write data, but
  390.                 this is a matter of "good luck". (Or, in other words, I don't
  391.                 want to document the messy details.)
  392.                 Please do only set this bit in case you really need the
  393.                 write data because it means much more work for the library
  394.                 and much "higher magic" to get it, especially for the 060
  395.                 CPU.
  396.  
  397.                 In case you want to allow the CPU to continue execution and
  398.                 you somehow managed to write out the data itself (or you
  399.                 want to ignore the faulty access), set the 
  400.                 EXDF_WRITECOMPLETE bit of the flags field below.
  401.  
  402.                 In case you do not set this bit, the CPU will attempt to
  403.                 re-run the faulty instruction. In case you haven't been able
  404.                 to repair the fault using some other techinque (as for
  405.                 example by swapping in the faulty page), your exception
  406.                 handler will be called again.
  407.  
  408.                 In case of a read fault, you may place the data to be 
  409.                 read back in this field and set the EXDF_READBACK flag
  410.                 in the flags value below. The MMU library will then
  411.                 attempt to place this value in the input pipe of the CPU
  412.                 and to repair the faulty access by providing this dummy
  413.                 data. The data has to be placed right-justified in this
  414.                 field again.
  415.  
  416.                 Certain restrictions arise, again:
  417.  
  418.                 First, a movem might show up as several exceptions, hence
  419.                 you might be able to provide data for each register loaded,
  420.                 or it might show up as one single exception. In this case,
  421.                 all registers will be loaded with the same value. (It was
  422.                 hard enough to emulate this, so please don't complain...)
  423.                 
  424.                 Instruction faults can't be repaired like this. (I would
  425.                 have been able to provide this exclusively for the 030 and
  426.                 the 020, but I choose not to do so for orthogonality).
  427.                 Don't try it, the mmu.library will call the exec exception
  428.                 handler directly in case you attempt this.
  429.  
  430. exd_ReturnPC    The program counter of the instruction that caused the
  431.                 fault. This is only an approximate value due to the 
  432.                 instruction prefetch feature of all CPUs of the 680x0
  433.                 family. In case a branch was performed after the faulty
  434.                 instruction was loaded, and before it was detected, this
  435.                 PC might be completely useless. However, the program
  436.                 is guaranteed to continue "at the right place".
  437.  
  438.                 In case you set the EXDF_CALL flag, this field contains
  439.                 the address of a small procedure which will be called in
  440.                 user mode, in the context of the task that caused the
  441.                 exception. This routine could, for example, send a message
  442.                 out to a "daemon" to get the fault repaired and could run
  443.                 into a WaitPort() to get an answer from the daemon.
  444.                 The user routine has access to all registers of the faulty 
  445.                 program, and must therefore preserve all registers unless 
  446.                 it attempts to alter them "on purpose". The exception data
  447.                 IS NO LONGER AVAILABLE, neither in the mmu library base
  448.                 nor in any register. If you want to make use of it, make a
  449.                 copy of it in the exception handler to a private place and
  450.                 access it in this user routine.
  451.  
  452.                 Alternatively, use the "message hook" mechanism of the
  453.                 library which provides all this for you already if you don't
  454.                 want to get a headache.
  455.  
  456.                 The user routine should then return with a "RTS" to the
  457.                 library code (note that the stacked PC points to some code
  458.                 in the library, not to the faulty code itself! It's truely
  459.                 deep magic to restore all this information) which will then    
  460.                 rerun the faulty instruction.
  461.  
  462.                 If you haven't been able to repair the cause of the fault,
  463.                 the exception hook will be called again!
  464.  
  465. exd_Flags        A combined input/output flags long word. Amongst private
  466.                 flags you'd better not care about, the following input
  467.                 flags are available:
  468.  
  469.     EXDF_WRITE            a write fault if set. If reset, a read fault.
  470.     EXDF_INSTRUCTION    a fault on fetching an instruction. 
  471.                         As a special case, this *could* be a write fault
  472.                         if someone tried to write out instruction data
  473.                         with an instruction function code using the 
  474.                         "moves" instruction. This is actually unsupported
  475.                         by the library and should not be tried.
  476.     EXDF_WRITEPROTECTED    failed due to write protection of the destination.
  477.     EXDF_SUPERVISOR        failed due to supervisor only protection of the
  478.                         source/destination.
  479.     EXDF_WRITEDATAUNKNOWN the write data was lost, exd_Data is invalid.
  480.                         Remember that you MUST set the MAPP_REPAIRABLE
  481.                         property flag for those pages you want write data
  482.                         for, and you should only set this bit if you really
  483.                         really want them. It means quite a lot of trouble
  484.                         for the library to provide the write data, hence
  485.                         things are not getting faster with it.
  486.     EXDF_MISALIGNED        The access was misaligned, i.e. more than one
  487.                         page was involved in the access. Prepare to
  488.                         swap in more than one page, for example.
  489.  
  490.                 The following flags can be set by your code to let the 
  491.                 library know what to do about the fault:
  492.  
  493.     EXDF_READBACK        abort a faulty read and provide the exd_Data word
  494.                         as input for the CPU. Do not try to rerun the access.
  495.     EXDF_WRITECOMPLETE    abort a faulty write, do not try to rerun it.
  496.     EXDF_CALL            call routine whose address is in exd_ReturnPC in
  497.                         user mode in the context of the task that caused
  498.                         the exception. This routine will be run as "sub-        
  499.                         routine" of the task that faulted, and might be
  500.                         used to sent out a message and wait for its reply
  501.                         to get the missing page fixed by another supervisor
  502.                         task. 
  503.                         THIS FUNCTION IS NOT AVAILABLE for the supervisor
  504.                         context. The mmu.library will guru in case you try
  505.                         to.
  506.                         Especially, the message hook mechanism described
  507.                         below uses this flag.
  508.                         Note that the library does not check for you whether
  509.                         Wait()-ing is useful here, as for example if the task
  510.                         is in Forbid state. It's the matter of the exception
  511.                         hook to check this.
  512.                         The library message hook exception does
  513.                         this, for example.
  514.  
  515. exd_Properties    The property flags of the page that was responsible for 
  516.                 the fault.
  517.  
  518. exd_NextProperties    In case of a misaligned access, the flags of the second 
  519.                 page involved in the access.
  520.  
  521. exd_internal        Leave this alone.
  522.  
  523. exd_FunctionCode    The function code of the access. The following values 
  524.                 should be expected:
  525.  
  526.                     For the user context hooks:
  527.         1                User data access
  528.         2                User code access
  529.  
  530.                     For the one and only supervisor context and its hooks:
  531.         5                Supervisor data access
  532.         6                Supervisor code access
  533.  
  534.                 All remaining function codes relate to physical bus errors 
  535.                 and should not be passed thru to your context hook.
  536.  
  537. exd_Level        The level of the MMU tree at which the access fault happend 
  538.                 and at which the MMU descriptor resides.
  539.                 This NEED NOT to be the "page level" for early termination 
  540.                 descriptors or invalid descriptors at a higher level. 
  541.                 Experts should note that this is not even guaranteed for
  542.                 the 040 or 060!
  543.                 Furthermore, in case of an indirect descriptor, this is the 
  544.                 level of the pointer pointing to the final page descriptor, 
  545.                 not the level of the real page descriptor. 
  546.                 
  547.                 This is advanced information you usually should not care 
  548.                 about.    
  549.  
  550.                 Level A of the MMU tree is encoded as "0", level B as "1" 
  551.                 and so on. Note that this numbering is different from the
  552.                 MC680x0 internal counting.
  553.  
  554.                 
  555. exd_NextLevel    In case of a misaligned access, the level of the second 
  556.                 descriptor involved in the fault.
  557.  
  558. exd_DataRegs    A copy of the data registers at the time the fault happened.
  559.                 These images are copied back as soon as the exception
  560.                 terminates, hence a "higher magic" exception handler could
  561.                 alter these...
  562.  
  563. exd_AddrRegs    A copy of the adress registers, but without the stack
  564.                 pointer.
  565.  
  566. exd_SSP            The supervisor stack pointer. This points directly to the
  567.                 processor specific exception stack frame. The first UWORD
  568.                 of this stack frame is the copy of the status register at
  569.                 the time of the fault.
  570.                 BE WARNED! Everything else is processor specific, the
  571.                 mmu.library might also want to modify this exception stack
  572.                 frame, so hands off!
  573.  
  574. exd_USP            The user stack pointer.
  575.  
  576. exd_SysBase        A pointer to the library base of the "exec.library". DO NOT 
  577.                 ACCESS ABSEXECBASE within the exception handler. Use either 
  578.                 a private copy, or this pointer.
  579.                 NOT FOLLOWING THIS RULE MIGHT BE FATAL!
  580.  
  581. exd_MMUBase        A pointer to the library base of the mmu.library, also in
  582.                 register a6.
  583.  
  584. Additional notes about the exception handlers
  585. ---------------------------------------------
  586.  
  587. In case you're going to write an automatic stack extension program, you
  588. should keep in mind that the EXDF_CALL - and therefore the message hook -
  589. mechanism requires about 300 bytes of user stack space. Similar, task
  590. switching takes some user stack, too. To be able to swap in stack in case
  591. of a stack overflow, a message hook alone WON'T DO GOOD for this reason.
  592.  
  593. Use the following mechanism:
  594.  
  595. -    Add a high-level exception hook that extends the user stack in super-
  596. visor mode with a "Last Chance" backup page you must have preallocated.
  597. Note that calling AllocMem() in supervisor mode is not permitted! 
  598.  
  599. Return with d0 not equal zero to allow the library to call all other hooks.
  600.  
  601.  
  602. -    Add a low-level message hook that captures the underflow and utilizes
  603. the stack you prepared in the high-level handler.
  604.  
  605.  
  606. For the same reason, you might have to add "Switch" and "Launch" handlers
  607. to allow execbase to store the user registers safely. Unfortunately, this
  608. is done with supervisor accessed going to the user stack, and not with a
  609. "moves".
  610.  
  611.  
  612. Additional wierdos to watch out for
  613. -----------------------------------
  614. There are unfortunately a number of "features" of each CPU which should not
  615. go unmentioned:
  616.  
  617. The 68020/68851 and 68030:
  618.  
  619.     Execution of instructions in a access-protected "zero page" is really,
  620.     really slow. Please keep this in mind!
  621.     "moves" to instruction space is unsupported (goes for all other CPUs
  622.     as well).
  623.  
  624.     The FPU and exceptions: This is a dark chapter in exception handling.
  625.     Of a faulty fmove, only the first two long words are checked by the
  626.     68030 and therefore at most two hits get reported, all others go
  627.     unnoticed. Of a faulty fmovem, only the first two long words hits get
  628.     reported, too. The CPU will ignore all other hits and continue 
  629.     execution.
  630.     This means specifically that a Debugger tool might not be able to see
  631.     all hits that happened on these instructions, and you will not be
  632.     able to capture them for private use.
  633.     VM systems shouldn't have much problems with that, though, since the
  634.     invalid page should have been swapped in and each access can hit at
  635.     most two pages at once if it is misaligned. However, you must be    
  636.     prepared that the mmu.library will not be able to set the "misaligned"
  637.     flag correctly in this case.
  638.  
  639. The 68040:
  640.  
  641.     Movem writeback data is not always available, and certain movems can't
  642.     be continued safely. In case a movem read or write goes to an invalid
  643.     page other than at level 2 or 3, the mmu library has to abort the movem
  644.     completely. There's nothing I can do against it. To avoid this situation
  645.     in case you really need the movem data, set the MAPP_REPAIRABLE property.
  646.  
  647.     Movems to a register included in the register list itself cannot be
  648.     rerun safely in all circumstances. Avoid them.
  649.  
  650.     Readback data is only available for all destination registers at once.
  651.  
  652.     The FPU and exceptions: Even more problems than with the 030. 
  653.     If a fmove or fmovem moves more than two long words, for example a
  654.     fmove.x or any fmovem, the processor will only notice the first 
  655.     access of a faulty page. If the instruction would catch more than
  656.     one hit, the processor restarts the instruction completely from the
  657.     beginning. This means for debugging tools that you will *not* be
  658.     able to fix a faulty instruction of this kind at all, the processor
  659.     will loop forever. Note that even disassembling the instruction at
  660.     the PC will not help because the PC might point to an FPU instruction
  661.     even if the hit was caused by the instruction before. Hence, the
  662.     following two instructions
  663.  
  664.         move.l d0,(a3)
  665.         fmovem.x fp0,(a3)
  666.  
  667.     with a3 pointing to an invalid page, will both invoke the exception
  668.     handler with the same PC value, namely the address of the fmovem.
  669.  
  670.     This might be a problem for VMM systems as well: Because there's no
  671.     single flag that tells whether the hit was caused by an FPU instruction
  672.     or not, the processor might re-run a FPU instruction as mentioned
  673.     above again, possibly accessing the two different pages. If the VMM
  674.     system would have swapped in the second page by the first hit, and
  675.     removed the first page accessed by this instruction from memory,
  676.     re-running this instruction will cause another VMM hit, this time
  677.     from the first page. It is therefore important that a VMM system
  678.     *MUST NOT* swap out a page previously swapped in. At least two pages
  679.     must be available at once.
  680.  
  681.  
  682. The 68060:
  683.  
  684.     The library handles branch cache flushes transparently, no need to
  685.     worry about them. So much for the good point.
  686.  
  687.     Writeback data is usually not available unless the library emulates
  688.     this with some heavy magic and is told to do so with the MAPP_REPAIRABLE
  689.     flag. Things are getting even worse if no exception handler wants to
  690.     make use of the writeback data and returns with the EXDF_WRITEBACK flag
  691.     cleared. In this case, the mmu.library tries to rerun the faulty 
  692.     instruction again, even though it already executed. It tries to rebuild
  693.     all the registers (except for the FPU registers and the supervisor model
  694.     and the SSP) and then returns to the PC of the faulty instruction.
  695.     Whether this mechanism is reliable or not has to be proven.
  696.  
  697.     Except that, all 040 restrictions regarding movems apply here again, see
  698.     above.
  699.  
  700.     In case of a non-locked read-modify-write access, as for example a
  701.     addq.l #1,(ax), the library will call the context hooks twice, once
  702.     with the read data, and then again with the write data. However, things
  703.     are getting rather nasty in case of a misaligned RMW access of which
  704.     one part of the access is valid and the other part is not. The 060
  705.     manual states that these accesses can't be rerun safely because parts
  706.     of the data might have been written back already, and rerunning the
  707.     instruction might cause this wrong data to be re-used again. I can't
  708.     comment on that feature because I haven't tried to reproduce it yet,
  709.     but it may reduce reliability of the 060 for virtual memory appli-
  710.     cations.
  711.  
  712. ------------------------------------------------------------------------------
  713.  
  714. About the page access exception:
  715.  
  716.  
  717. This is not a true exception, but is installed and handled the like. It is
  718. setup with AddContextHook(MADTAG_TYPE,MMUEH_PAGEACCESS,....) as all other
  719. exception handlers. The page access hook "hooks in" between the high level
  720. functions SetProperties/GetProperties/RebuildTree and the low level functions
  721. SetPageProperties/GetPageProperties at the other side. It provides a method
  722. to modify the MMU tree on the low level transparently to the high level 
  723. functions. 
  724.  
  725. The page access handlers are called whenever RebuildTree() tries to re-
  726. install a page descriptor with the MAPP_SINGLE property bit set. If so, your
  727. handler is allowed to modify this page descriptor. However, you should 
  728. remember that the high-level functions are not aware of this modification,
  729. so this feature should be used carefully.
  730.  
  731. A possible application would be a "Guardian Angel" type program: The idea
  732. is here to mark "free" memory as MAPP_INVALID to be able to detect illegal
  733. memory accesses. Since an AllocMem() has to mark the memory valid it
  734. allocated, the MMU tables have to be adjusted for each allocation. Similary,
  735. released memory has to be made unavailable on a FreeMem(). On the 
  736. other hand, AllocMem() is not allowed to break a Forbid() and is hence not
  737. able to call the high-level functions - which might do so. It *has* to use
  738. the low level SetPageProperties(). Since the low level functions do not
  739. inform the higher level about the modification, a program adjusting the
  740. MMU descriptor with the high-level functions will un-do the modifications
  741. made by AllocMem() before. The solution here is to install a page access 
  742. handler that checks whether the higher level is going to re-install one
  743. of the modified page descriptors, to intercept here and to set the 
  744. MAPP_INVALID flag correctly, by testing whether the addressed memory page is
  745. "free" or not.
  746.  
  747.  
  748.  
  749. Your handler is called with the page access data structure - see below - in
  750. a0, with the provided user data from MADTAD_DATA in a1 and a4 and the 
  751. library pointer in a6. Registers d0-d1/a0-a1/a4-a5 are scratch registers,
  752. a6 IS NOT. In case your handler returns with the Z flag set, the library
  753. aborts calling other handlers of lower priority.
  754.  
  755. Remember that you're called in supervisor mode with all interrupts dis-
  756. abled, as for all other exception handlers. Your code should better be
  757. fast!
  758.  
  759.  
  760. Now for the structure:
  761.  
  762. struct PageAccessData {
  763.         ULONG                    pgad_Level;
  764.         void                    *pgad_Address;
  765.         ULONG                   *pgad_Destination;
  766.         struct MMUContext       *pgad_Context;
  767.         struct MMUBase          *pgad_MMUBase;
  768.         ULONG                    pgad_Properties;
  769.         ULONG                    pgad_UserData;
  770. };
  771.  
  772.  
  773. pgad_Level:            The level at which the MMU descriptor has to be build
  774.                     for. This is zero for level A, one for level B and so
  775.                     on. Note that this numbering is different from the
  776.                     internal MC68K scheme.
  777.                     Since this handler is only called for MAPP_SINGLE
  778.                     descriptors, this will always be the page level of the
  779.                     MMU tree. However, what the page level *is* is up to
  780.                     the depth of the MMU tree and may vary.
  781.  
  782. pgad_Address:        The logical address the descriptor to be build will 
  783.                     handle. Hence, this gives the address that is to be
  784.                     translated or mapped.
  785.  
  786. pgad_Destination:    The address the true hardware descriptor will be written
  787.                     to. There's little reason to make use of this entry.
  788.  
  789. pgad_Context:        The context the MMU tree being rebuild belongs to. This
  790.                     is the context you installed the page access handler in.
  791.  
  792. pgad_MMUBase:        The library base address.
  793.  
  794. pgad_Properties:    The page properties, defined in mmu/context.h. This 
  795.                     defines which kind of hardware descriptor the library
  796.                     will build for you.
  797.  
  798. pgad_UserData:        This field will be used for MAPP_SWAPPED, MAPP_INVALID,
  799.                     MAPP_REMAPPED, MAPP_BUNDLED and MAPP_INDIRECT 
  800.                     descriptors. It will contain user specific information
  801.                     like a hard disk position for MAPP_SWAPPED or 
  802.                     MAPP_INVALID pages, the destination address for 
  803.                     MAPP_REMAPPED and MAPP_BUNDLED pages, and the destination
  804.                     descriptor for MAPP_INDIRECT. It is not available if the
  805.                     MAPP_REPAIRABLE bit is set. In case you modify the
  806.                     properties, you possibly need to correct this field, too.
  807.  
  808.